#ifndef MCGPP_ML_COARSENER_H
#define MCGPP_ML_COARSENER_H

#include "coarsener_base.h"
#include "refine_info.h"
#include "policies/rating_tie_breaking_policy.h"
#include "vertex_pair_rater.h"

//n-level缩合还原
//1.缩合先不考虑优化
//2.还原使用细粒度的n-level优化
namespace mcgpp {
  template<class AcceptancePolicy = BestRatingPreferringUnmatched<>>
  class MLCoarsener : public CoarsenBase {
  public:
    MLCoarsener(ds::GenericGraph &graph) : CoarsenBase(graph),
                                           _rater(graph) {

    }

    ~MLCoarsener() override = default;

    void coarsenImpl(int limit) override {
      int pass_iter = 0;
      _current_level_total_node_num.clear();
      _current_level_total_node_num.emplace_back(_g._current_num_nodes);

      std::vector<IDType> current_ns;
      while (_g._current_num_nodes > limit) {

        const IDType num_ns_before_pass = _g._current_num_nodes;
        for (auto v: _g._current_node_set)
          current_ns.emplace_back(v);
        Randomize::instance().shuffleVector(current_ns, current_ns.size());

        for (IDType v: current_ns) {
          if (_g.nodeIsEnabled(v)) {
//            VertexPairRating rating = _rater.rate2(v);//考虑质量的缩合，貌似比重边效果好
            VertexPairRating rating = _rater.rate(v);//重边缩合

            if (rating.valid) {
              //标记
              _rater.markAsMatched(v);
              _rater.markAsMatched(rating.target);

              //缩合
              performContraction(v, rating.target);
            }
            if (_g._current_num_nodes <= limit) {
              break;
            }
          }
        }
        //本轮缩合顶点数没有变化则退出缩合
        if (num_ns_before_pass == _g._current_num_nodes) {
          break;
        }

        current_ns.clear();
        _rater.resetMatches();
        ++pass_iter;
        //记录当前顶点数
        _current_level_total_node_num.emplace_back(_g._current_num_nodes);
      }
      DBG << "pass iter:" << pass_iter;
      for (auto x: _current_level_total_node_num)
        DBG << x;
    }

    void uncontract() {
      _graph_pruner.restoreParallelEdges(_g, _history.back());
      _graph_pruner.restoreSingleEdges(_g, _history.back());

      _g.uncontract(_history.back().contraction_memento);
      _history.pop_back();


    }

    //直接进行还原搜索
    void uncoarsenImpl(RefinerBase &refiner, Metrics &f_best) override {
      //do nothing
      int level = 0;
      std::vector<IDType> refine_nodes;
      RefineInfo refineInfo;//记录搜索的目标值变化信息
      //初始化
      metrics::conductance(_g, f_best);

      while (!_history.empty()) {
        if (Timer::instance().TLE()) {
          //到时间了
          while (!_history.empty())
            performUncontraction();
          metrics::conductance(_g, f_best);
          break;
        }
        //还原到下一个阶段
        _current_level_total_node_num.pop_back();
        //记录搜索前目标函数值
        refineInfo.before_refine_obj = f_best.conductance / 1e10;
        double before_true_obj = refiner.getTrueObj();

        while (_g._current_num_nodes < _current_level_total_node_num.back()) {
          //实际还原一对顶点
          refine_nodes.clear();
          refine_nodes.emplace_back(_history.back().contraction_memento.u);
          refine_nodes.emplace_back(_history.back().contraction_memento.v);
          performUncontraction();

          refiner.refineImpl(refine_nodes, f_best);
        }
        //记录搜索后目标函数值
        refineInfo.after_refine_obj = f_best.conductance / 1e10;
        double after_true_obj = refiner.getTrueObj();
        //记录是否优化当前解
        int cur_level = _current_level_total_node_num.end() - _current_level_total_node_num.begin();
        refineInfo.impove = refineInfo.after_refine_obj < refineInfo.before_refine_obj ? 1 : 0;
        LOG
        << "level:" << cur_level << "nodeNum:" << _g._current_num_nodes << refineInfo.before_refine_obj
        << refineInfo.after_refine_obj << refineInfo.impove;
        LOG << before_true_obj << after_true_obj;

      }

    }

    VertexPairRater<AcceptancePolicy> _rater; // 管理打分操作

  };
}
#endif //MCGPP_ML_COARSENER_H
